#include "SANServer.h"

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;

SANServer::SANServer()
{
    iBuf = (char*)calloc(DATA_LEN, sizeof(char));
    iLen = 0;
    iCount = 0;
    iDroppedCount = 0;
    fp = fopen("size.txt","w");
}

SANServer::~SANServer()
{
    fclose(fp);
    delete iBuf;
    close(iServSockFd);
    close(iBlankSockFd);
}

void SANServer::SetMaxClients(int aMaxClients)
{
    iMaxClients = aMaxClients;
}

void SANServer::SetServerPort(int aPort)
{
    iPort = aPort;
}

bool SANServer::SetupConnection()
{

    iServSockFd = socket(AF_INET, SOCK_STREAM, 0);
    iServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    iServAddr.sin_family = AF_INET;
    iServAddr.sin_port = htons(iPort);

    if(iServSockFd < 0)
        return false;
    else
        return true;
}

int SANServer::StartServer()
{
    if(bind(iServSockFd, (struct sockaddr*)&iServAddr, sizeof(iServAddr)) < 0)
        return KBindFail;

    if(listen(iServSockFd, iMaxClients) < 0)
        return KListenFail;

    return KSuccess;
}


int SANServer::AcceptClients()
{
    int blankfd = accept(iServSockFd, 0, 0);
    if(blankfd < 0)
        return KAcceptFail;
    else
        return blankfd;
}

void SANServer::RecvData()
{
    QString temp;
    while(true)
    {
        bzero(iBuf, DATA_LEN);
        iLen = recv(iBlankSockFd, (char*)iBuf, DATA_LEN, 0);

        temp.clear();
        temp.append(iBuf);
        //to display recd data in UI
        //emit EmitDataReceived(temp);
        if(iLen > 0)
        {

            //rite the current q length to the file
            bzero(iBuf, DATA_LEN);
            sprintf(iBuf, "%d", iServerQueue.size());
            fwrite(iBuf, sizeof(char), DATA_LEN, fp);
            bzero(iBuf, DATA_LEN);
            strcpy(iBuf, "\n");
            fwrite(iBuf, sizeof(char), DATA_LEN, fp);


            iCount++;
            if(iServerQueue.size() > SERVER_QUEUE_SIZE)
            {
                iDroppedCount++;
            }
            else
            {
                pthread_mutex_lock(&mutex1);
                iServerQueue.append(temp);
                pthread_mutex_unlock(&mutex1);
                //emit EmitSortData();
            }
        }
    }
}

void SANServer::run(void)
{
    int status = true;

    //setup the server first
    if(SetupConnection() == false)
        status = false;

    //do bind and listen
    int status_1 = StartServer();
    if(status_1 == 0 && status == true)
        emit EmitServerConnected(true);
    else
        emit EmitServerConnected(false);

    //perform accept here
    iBlankSockFd = AcceptClients();
    if(iBlankSockFd > 0)
    {
        emit EmitClientAccepted(true);
        RecvData();
    }
    else
    {
        emit EmitClientAccepted(false);
    }
}

char* SANServer::GetBuffer()
{
    return iBuf;
}

long long int SANServer::GetCount()
{
    return iCount;
}

long long int SANServer::GetDroppedCount()
{
    return iDroppedCount;
}

void SANServer::DecrementCount()
{
    iCount--;
}

SANSorting::SANSorting(SANServer *aServer)
{
    iServer = aServer;
    iBuf = (char*)calloc(DATA_LEN, sizeof(char));
    iCount = 0;
}

SANSorting::~SANSorting()
{
    if(iBuf)
        free(iBuf);
    close(iSockFd);
}

void SANSorting::ConnectSortingThread()
{

    if(SetupConnection() == false)
    {
        emit EmitServerToClient(false);
    }
    else
    {
        if(ConnectToClient() == false)
        {
            emit EmitServerToClient(false);
        }
        else
        {
            emit EmitServerToClient(true);

        }
    }

}

void SANSorting::run(void)
{
    QByteArray e;
    while(true)
    {
        pthread_mutex_lock(&mutex1);
        if(iServer->iServerQueue.isEmpty() == false)
            e = iServer->iServerQueue.takeFirst().toUtf8();
        pthread_mutex_unlock(&mutex1);

        if(e != NULL)
        {
            char *buf = e.data();
            char temp;

            for(int j = 0; j < DATA_LEN; j ++)
            {
                for(int i = 0; i < DATA_LEN-1; i++)
                {
                    if(buf[i] > buf[i+1])
                    {
                        temp = buf[i];
                        buf[i] = buf[i+1];
                        buf[i+1] = temp;
                    }
                }
            }
            send(iSockFd, buf, DATA_LEN, 0);
            iCount++;
        }
        //to display sorted data in UI
        //emit EmitDisplaySortedData(buf);
    }
}

void SANSorting::SetIp(std::string aIp)
{
    iIp = aIp;
}

void SANSorting::SetPort(int aPort)
{
    iPort = aPort;
}

int SANSorting::GetPort()
{
    return iPort;
}

std::string SANSorting::GetIp()
{
    return iIp;
}

bool SANSorting::SetupConnection()
{
    const char *ip = iIp.c_str();
    iSockFd = socket(AF_INET, SOCK_STREAM, 0);
    iClientAddr.sin_addr.s_addr = inet_addr(ip);
    iClientAddr.sin_port = htons(iPort);
    iClientAddr.sin_family = AF_INET;

    if(iSockFd > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool SANSorting::ConnectToClient()
{
    if(::connect(iSockFd, (struct sockaddr*)&iClientAddr, sizeof(iClientAddr)) < 0)
        return false;
    else
        return true;
}

long long int SANSorting::GetCount()
{
    return iCount;
}
